-------------------------------------------------------------
--ECE 251 Switch - Validity Parser block - by Peter Gebhard--
-------------------------------------------------------------

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
USE ieee.std_logic_arith.all;

ENTITY validity_parser IS
   PORT(clk     : IN   STD_LOGIC;
        d       : IN   STD_LOGIC_VECTOR(3 DOWNTO 0);
        d_valid : IN   STD_LOGIC;
        
        drop_frame   : OUT  STD_LOGIC;
        end_of_frame : BUFFER  STD_LOGIC;
        hdr_ready    : BUFFER  STD_LOGIC;
		  mac_dest	   : OUT  STD_LOGIC_VECTOR(47 DOWNTO 0);
		  mac_src		: OUT  STD_LOGIC_VECTOR(47 DOWNTO 0);
        length       : BUFFER  STD_LOGIC_VECTOR(15 DOWNTO 0);
        q            : OUT  STD_LOGIC_VECTOR(3 DOWNTO 0);
        q_valid      : OUT  STD_LOGIC
        );        
END validity_parser;

ARCHITECTURE Behavior OF validity_parser IS

SUBTYPE header_width IS STD_LOGIC_VECTOR(3 DOWNTO 0);
TYPE header_length IS ARRAY (43 DOWNTO 0) OF header_width;

SIGNAL header : header_length;
signal count: std_logic_vector(5 downto 0);
signal countLen: std_logic_vector(15 downto 0);
signal good_frame: std_logic;
signal started_frame: std_logic;

BEGIN   
   PROCESS (clk)
   BEGIN
      IF (clk'EVENT AND clk = '1') THEN
         IF (d_valid = '1') THEN
			
   			IF (count = "000000") THEN
   				end_of_frame <= '0';
   				hdr_ready <= '0';
   				drop_frame <= '0';
   				header(43) <= d;
   			ELSIF (count = "000001") THEN
   				header(42) <= d;
   			ELSIF (count = "000010") THEN
   				header(41) <= d;				
   			ELSIF (count = "000011") THEN
   				header(40) <= d;				
   			ELSIF (count = "000100") THEN
   				header(39) <= d;				
   			ELSIF (count = "000101") THEN
   				header(38) <= d;				
   			ELSIF (count = "000110") THEN
   				header(37) <= d;				
   			ELSIF (count = "000111") THEN
   				header(36) <= d;				
   			ELSIF (count = "001000") THEN
   				header(35) <= d;				
   			ELSIF (count = "001001") THEN
   				header(34) <= d;				
   			ELSIF (count = "001010") THEN
   				header(33) <= d;				
   			ELSIF (count = "001011") THEN
   				header(32) <= d;
   			ELSIF (count = "001100") THEN
   				header(31) <= d;		
   			ELSIF (count = "001101") THEN
   				header(30) <= d;				
   			ELSIF (count = "001110") THEN
   				header(29) <= d;				
   			ELSIF (count = "001111") THEN
   				header(28) <= d;				
   			ELSIF (count = "010000") THEN
   				header(27) <= d;				
   			ELSIF (count = "010001") THEN
   				header(26) <= d;				
   			ELSIF (count = "010010") THEN
   				header(25) <= d;				
   			ELSIF (count = "010011") THEN
   				header(24) <= d;				
   			ELSIF (count = "010100") THEN
   				header(23) <= d;				
   			ELSIF (count = "010101") THEN
   				header(22) <= d;
   			ELSIF (count = "010110") THEN
   				header(21) <= d;				
   			ELSIF (count = "010111") THEN
   				header(20) <= d;				
   			ELSIF (count = "011000") THEN
   				header(19) <= d;				
   			ELSIF (count = "011001") THEN
   				header(18) <= d;				
   			ELSIF (count = "011010") THEN
   				header(17) <= d;				
   			ELSIF (count = "011011") THEN
   				header(16) <= d;				
   			ELSIF (count = "011100") THEN
   				header(15) <= d;				
   			ELSIF (count = "011101") THEN
   				header(14) <= d;				
   			ELSIF (count = "011110") THEN
   				header(13) <= d;				
   			ELSIF (count = "011111") THEN
   				header(12) <= d;
   			ELSIF (count = "100000") THEN
   				header(11) <= d;				
   			ELSIF (count = "100001") THEN
   				header(10) <= d;				
   			ELSIF (count = "100010") THEN
   				header(9) <= d;				
   			ELSIF (count = "100011") THEN
   				header(8) <= d;				
   			ELSIF (count = "100100") THEN
   				header(7) <= d;				
   			ELSIF (count = "100101") THEN
   				header(6) <= d;				
   			ELSIF (count = "100110") THEN
   				header(5) <= d;				
   			ELSIF (count = "100111") THEN
   				header(4) <= d;				
   			ELSIF (count = "101000") THEN
   				header(3) <= d;				
   			ELSIF (count = "101001") THEN
   				header(2) <= d;
   			ELSIF (count = "101010") THEN
   				header(1) <= d;				
   			ELSIF (count = "101011") THEN
   				header(0) <= d;
   			END IF;
			
   			IF (count = "010000") THEN
   				 IF (header(43) = "1010" AND header(42) = "1010" AND header(41) = "1010" AND header(40) = "1010" AND header(39) = "1010" AND header(38) = "1010" AND header(37) = "1010" AND header(36) = "1010" AND header(35) = "1010" AND header(34) = "1010" AND header(33) = "1010" AND header(32) = "1010" AND header(31) = "1010" AND header(30) = "1010" AND header(29) = "1010" AND header(28) = "1011") THEN
   					started_frame <= '1';
   					q <= d;
   					q_valid <= '1';
   				 END IF;
   			END IF;
			
   			IF (count /= "101100") THEN
   				hdr_ready <= '0';
   				count <= count + 1;
   			END IF;
			
   			IF (count = "101100" AND countLen = "0000000000000000" AND hdr_ready = '0' AND started_frame = '1') THEN

   				length(15 DOWNTO 12) <= header(3);
   				length(11 DOWNTO 8) <= header(2);
   				length(7 DOWNTO 4) <= header(1);
   				length(3 DOWNTO 0) <= header(0);
			
--   				countLen(15 DOWNTO 12) <= header(3);
--   				countLen(11 DOWNTO 8) <= header(2);
--   				countLen(7 DOWNTO 4) <= header(1);
--   				countLen(3 DOWNTO 0) <= header(0);

--   				countLen(16 DOWNTO 13) <= header(3);
   				countLen(12 DOWNTO 9) <= header(2);
   				countLen(8 DOWNTO 5) <= header(1);
   				countLen(4 DOWNTO 1) <= header(0);

--				countLen(15 DOWNTO 1) <= countLen(14 DOWNTO 0);
				
   				for I in 0 to 11 loop
   				   	mac_dest(4*(I+1)-1 DOWNTO 4*I) <= header(16+I);
   				end loop;
				
   				for I in 0 to 11 loop
   				   	mac_src(4*(I+1)-1 DOWNTO 4*I) <= header(4+I);
   				end loop;

   				hdr_ready <= '1';
   			END IF;
			
   			IF (started_frame = '1') THEN
   				q <= d;
   				q_valid <= '1';
				
   				IF (hdr_ready = '1') THEN
   					countLen <= countLen - 1;
   					
   					IF (header(27 DOWNTO 16) = header(15 DOWNTO 4)) THEN
                     drop_frame <= '1';
                     count <= "000000";
                     q_valid <= '0';
                     hdr_ready <= '0';
                  END IF;
					
   					IF (countLen = "0000000000000000") THEN
   						end_of_frame <= '1';
   						hdr_ready <= '0';
   						started_frame <= '0';
   						count <= "000000";
   						q_valid <= '0';
   					END IF;
   				END IF;
   			END IF;
		
         END IF;

		 IF (d_valid = '0') THEN
			q_valid <= '0';
			count <= "000000";
			end_of_frame <= '1';
			started_frame <= '0';
			hdr_ready <= '0';
			drop_frame <= '0';
		 END IF;

      END IF;
   END PROCESS;
END Behavior;